package com.biodiv.miracle.aop.proxy;

import net.bytebuddy.ByteBuddy;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.implementation.bind.annotation.AllArguments;
import net.bytebuddy.implementation.bind.annotation.Origin;
import net.bytebuddy.implementation.bind.annotation.RuntimeType;
import net.bytebuddy.matcher.ElementMatchers;

import java.lang.reflect.Method;
import java.util.List;

/**
 * @Author: tianquan
 * @CreateTime: 2025-05-25  11:59
 * @Description: 使用buddy代理
 */
public class ByteBuddyProxyHandler extends AbstractMethodInvocation {

    /**
     * 构造函数，初始化代理对象、方法列表和增强方法
     *
     * @param object           需要代理的对象
     * @param objectMethodName 需要代理的方法名称列表
     * @param beforeMethod     前置增强方法
     * @param aroundMethod     环绕增强方法
     * @param afterMethod      后置增强方法
     * @param target           调用增强方法的目标对象
     */
    public ByteBuddyProxyHandler(Object object, List<String> objectMethodName, Method beforeMethod,
                                 Method aroundMethod, Method afterMethod, Object target) {
        this.object = object;
        this.objectMethodName = objectMethodName;
        this.beforeMethod = beforeMethod;
        this.aroundMethod = aroundMethod;
        this.afterMethod = afterMethod;
        this.target = target;
    }

    @RuntimeType
    public Object intercept(@Origin Method method, @AllArguments Object[] args) throws Throwable {
        return invokeMethod(null, method, args);
    }

    @Override
    public Object getProxy() throws Throwable {
        Class<?> targetClass = object.getClass();
        DynamicType.Unloaded<?> dynamicType = new ByteBuddy()
                .subclass(targetClass)
                .method(ElementMatchers.any().and(ElementMatchers.not(ElementMatchers.isDeclaredBy(Object.class))))
                .intercept(MethodDelegation.to(this))
                .make();
        // 使用目标类的类加载器加载生成的代理类
        Class<?> proxyClass = dynamicType.load(targetClass.getClassLoader()).getLoaded();
        return proxyClass.getDeclaredConstructor().newInstance();

    }

}
